package dragon.social.core.QQ.api;

import com.fasterxml.jackson.databind.ObjectMapper;
import dragon.social.core.ConstantProperties;
import dragon.social.core.QQ.QQServiceProvider;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.social.oauth2.AbstractOAuth2ApiBinding;
import org.springframework.social.oauth2.TokenStrategy;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;

/**
 * accessToken是存储前5步最终得到的token，由此可见，Api不是单例模式，而是每个用户一个实例。
 * 因此也不用担心openId覆盖的问题
 */
public class QQApiImpl extends AbstractOAuth2ApiBinding implements QQApi{

    Logger logger = LoggerFactory.getLogger(QQApiImpl.class);
    /**
     * QQ的用户信息api详见此页面 https://wiki.connect.qq.com/get_user_info
     *  调用地址: https://graph.qq.com/user/get_user_info?access_token=YOUR_ACCESS_TOKEN&oauth_consumer_key=YOUR_APP_ID&openid=YOUR_OPENID
     * 调用所有OpenAPI时，除了各接口私有的参数外，所有OpenAPI都需要传入基于OAuth2.0协议的通用参数：
     *
     * 参数	含义
     * access_token	        可通过使用Authorization_Code获取Access_Token 或来获取。 access_token有3个月有效期。
     * oauth_consumer_key	申请QQ登录成功后，分配给应用的appid
     * openid	            用户的ID，与QQ号码一一对应。可通过调用https://graph.qq.com/oauth2.0/me?access_token=YOUR_ACCESS_TOKEN 来获取。
     *
     *
     * AbstractOAuth2ApiBinding 已经提供了access_token，所以这里要定义余下两个参数appid和openid
     * 另外，由于appid是固定的，所以直接在constant中写死，那就只剩下openid了
     */
    private String openId;
    private String appId;

    /**
     * jackson的json转换器
     */
    private ObjectMapper objectMapper = new ObjectMapper();

    public QQApiImpl(String accessToken,String appId) {
        /*这里要调用两个参数的父类构造方法。因为单参数的构造方法，是把token放在请求头上。而QQ要求放在请求体中，所以要重新定义
        TokenStrategy是token策略
        * */
        super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);
        this.appId = appId;
        this.openId = getOpenIdFromQQ(accessToken);
    }

    @Override
    public QQUserinfo getQQUser() {
        //父层策略会自动把access_token放到url中，所以这里不需要填入，详见QQApiImpl构造说明
        String getUserUrl = String.format(ConstantProperties.QQ_GET_USER_INFO_URL, appId,openId);
        RestTemplate restTemplate = getRestTemplate();
        String openIdResult = restTemplate.getForObject(getUserUrl, String.class);
        System.out.println("获取User信息结果：" + openIdResult);
        try {
            QQUserinfo qqUserinfo = objectMapper.readValue(openIdResult, QQUserinfo.class);
            qqUserinfo.setOpenId(openId);
            return qqUserinfo;
        } catch (IOException e) {
            throw new RuntimeException("get QQ user info fail in trans json to entity:" + openIdResult,e);
        }
    }

    /**
     * 从QQ获取openId
     * 参考文档 https://wiki.connect.qq.com/%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7openid_oauth2-0
     * @param accessToken
     * @return
     */
    public String getOpenIdFromQQ(String accessToken){
        String openIdUrl = String.format(ConstantProperties.QQ_GET_OPEN_ID_URL,accessToken);
        RestTemplate restTemplate = getRestTemplate();
        String openIdResult = restTemplate.getForObject(openIdUrl, String.class);
        logger.info("获取openId结果：" + openIdResult);
        //这里还需要截取qq openid的返回信息,QQ openId的格式为：callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} );
        String openId = StringUtils.substringBetween(openIdResult, "openid\":\"", "\"}");
        return openId;
    }
}
